1 /**
  2  * Constructs a new mark with default properties. Marks, with the exception of
  3  * the root panel, are not typically constructed directly; instead, they are
  4  * added to a panel or an existing mark via {@link pv.Mark#add}.
  5  *
  6  * @class Represents a data-driven graphical mark. The <tt>Mark</tt> class is
  7  * the base class for all graphical marks in Protovis; it does not provide any
  8  * specific rendering functionality, but together with {@link Panel} establishes
  9  * the core framework.
 10  *
 11  * <p>Concrete mark types include familiar visual elements such as bars, lines
 12  * and labels. Although a bar mark may be used to construct a bar chart, marks
 13  * know nothing about charts; it is only through their specification and
 14  * composition that charts are produced. These building blocks permit many
 15  * combinatorial possibilities.
 16  *
 17  * <p>Marks are associated with <b>data</b>: a mark is generated once per
 18  * associated datum, mapping the datum to visual <b>properties</b> such as
 19  * position and color. Thus, a single mark specification represents a set of
 20  * visual elements that share the same data and visual encoding. The type of
 21  * mark defines the names of properties and their meaning. A property may be
 22  * static, ignoring the associated datum and returning a constant; or, it may be
 23  * dynamic, derived from the associated datum or index. Such dynamic encodings
 24  * can be specified succinctly using anonymous functions. Special properties
 25  * called event handlers can be registered to add interactivity.
 26  *
 27  * <p>Protovis uses <b>inheritance</b> to simplify the specification of related
 28  * marks: a new mark can be derived from an existing mark, inheriting its
 29  * properties. The new mark can then override properties to specify new
 30  * behavior, potentially in terms of the old behavior. In this way, the old mark
 31  * serves as the <b>prototype</b> for the new mark. Most mark types share the
 32  * same basic properties for consistency and to facilitate inheritance.
 33  *
 34  * <p>The prioritization of redundant properties is as follows:<ol>
 35  *
 36  * <li>If the <tt>width</tt> property is not specified (i.e., null), its value
 37  * is the width of the parent panel, minus this mark's left and right margins;
 38  * the left and right margins are zero if not specified.
 39  *
 40  * <li>Otherwise, if the <tt>right</tt> margin is not specified, its value is
 41  * the width of the parent panel, minus this mark's width and left margin; the
 42  * left margin is zero if not specified.
 43  *
 44  * <li>Otherwise, if the <tt>left</tt> property is not specified, its value is
 45  * the width of the parent panel, minus this mark's width and the right margin.
 46  *
 47  * </ol>This prioritization is then duplicated for the <tt>height</tt>,
 48  * <tt>bottom</tt> and <tt>top</tt> properties, respectively.
 49  *
 50  * <p>While most properties are <i>variable</i>, some mark types, such as lines
 51  * and areas, generate a single visual element rather than a distinct visual
 52  * element per datum. With these marks, some properties may be <b>fixed</b>.
 53  * Fixed properties can vary per mark, but not <i>per datum</i>! These
 54  * properties are evaluated solely for the first (0-index) datum, and typically
 55  * are specified as a constant. However, it is valid to use a function if the
 56  * property varies between panels or is dynamically generated.
 57  *
 58  * <p>See also the <a href="../../api/">Protovis guide</a>.
 59  */
 60 pv.Mark = function() {
 61   /*
 62    * TYPE 0 constant defs
 63    * TYPE 1 function defs
 64    * TYPE 2 constant properties
 65    * TYPE 3 function properties
 66    * in order of evaluation!
 67    */
 68   this.$properties = [];
 69 };
 70 
 71 /** @private TOOD */
 72 pv.Mark.prototype.properties = {};
 73 
 74 /**
 75  * @private Defines and registers a property method for the property with the
 76  * given name.  This method should be called on a mark class prototype to define
 77  * each exposed property. (Note this refers to the JavaScript
 78  * <tt>prototype</tt>, not the Protovis mark prototype, which is the {@link
 79  * #proto} field.)
 80  *
 81  * <p>The created property method supports several modes of invocation: <ol>
 82  *
 83  * <li>If invoked with a <tt>Function</tt> argument, this function is evaluated
 84  * for each associated datum. The return value of the function is used as the
 85  * computed property value. The context of the function (<tt>this</tt>) is this
 86  * mark. The arguments to the function are the associated data of this mark and
 87  * any enclosing panels. For example, a linear encoding of numerical data to
 88  * height is specified as
 89  *
 90  * <pre>m.height(function(d) d * 100);</pre>
 91  *
 92  * The expression <tt>d * 100</tt> will be evaluated for the height property of
 93  * each mark instance. The return value of the property method (e.g.,
 94  * <tt>m.height</tt>) is this mark (<tt>m</tt>)).<p>
 95  *
 96  * <li>If invoked with a non-function argument, the property is treated as a
 97  * constant. The return value of the property method (e.g., <tt>m.height</tt>)
 98  * is this mark.<p>
 99  *
100  * <li>If invoked with no arguments, the computed property value for the current
101  * mark instance in the scene graph is returned. This facilitates <i>property
102  * chaining</i>, where one mark's properties are defined in terms of another's.
103  * For example, to offset a mark's location from its prototype, you might say
104  *
105  * <pre>m.top(function() this.proto.top() + 10);</pre>
106  *
107  * Note that the index of the mark being evaluated (in the above example,
108  * <tt>this.proto</tt>) is inherited from the <tt>Mark</tt> class and set by
109  * this mark. So, if the fifth element's top property is being evaluated, the
110  * fifth instance of <tt>this.proto</tt> will similarly be queried for the value
111  * of its top property. If the mark being evaluated has a different number of
112  * instances, or its data is unrelated, the behavior of this method is
113  * undefined. In these cases it may be better to index the <tt>scene</tt>
114  * explicitly to specify the exact instance.
115  *
116  * </ol><p>Property names should follow standard JavaScript method naming
117  * conventions, using lowerCamel-style capitalization.
118  *
119  * <p>In addition to creating the property method, every property is registered
120  * in the {@link #properties} map on the <tt>prototype</tt>. Although this is an
121  * instance field, it is considered immutable and shared by all instances of a
122  * given mark type. The <tt>properties</tt> map can be queried to see if a mark
123  * type defines a particular property, such as width or height.
124  *
125  * @param {string} name the property name.
126  */
127 pv.Mark.prototype.property = function(name) {
128   if (!this.hasOwnProperty("properties")) {
129     this.properties = pv.extend(this.properties);
130   }
131   this.properties[name] = true;
132 
133   /*
134    * Define the setter-getter globally, since the default behavior should be the
135    * same for all properties, and since the Protovis inheritance chain is
136    * independent of the JavaScript inheritance chain. For example, anchors
137    * define a "name" property that is evaluated on derived marks, even though
138    * those marks don't normally have a name.
139    */
140   pv.Mark.prototype[name] = function(v) {
141       if (arguments.length) {
142         this.$properties.push({
143             name: name,
144             type: (typeof v == "function") ? 3 : 2,
145             value: v
146           });
147         return this;
148       }
149       return this.scene[this.index][name];
150     };
151 
152   return this;
153 };
154 
155 /* Define all global properties. */
156 pv.Mark.prototype
157     .property("data")
158     .property("visible")
159     .property("left")
160     .property("right")
161     .property("top")
162     .property("bottom")
163     .property("cursor")
164     .property("title")
165     .property("reverse");
166 
167 /**
168  * The mark type; a lower camelCase name. The type name controls rendering
169  * behavior, and unless the rendering engine is extended, must be one of the
170  * built-in concrete mark types: area, bar, dot, image, label, line, panel,
171  * rule, or wedge.
172  *
173  * @type string
174  * @name pv.Mark.prototype.type
175  */
176 
177 /**
178  * The mark prototype, possibly undefined, from which to inherit property
179  * functions. The mark prototype is not necessarily of the same type as this
180  * mark. Any properties defined on this mark will override properties inherited
181  * either from the prototype or from the type-specific defaults.
182  *
183  * @type pv.Mark
184  * @name pv.Mark.prototype.proto
185  */
186 
187 /**
188  * The enclosing parent panel. The parent panel is generally undefined only for
189  * the root panel; however, it is possible to create "offscreen" marks that are
190  * used only for inheritance purposes.
191  *
192  * @type pv.Panel
193  * @name pv.Mark.prototype.parent
194  */
195 
196 /**
197  * The child index. -1 if the enclosing parent panel is null; otherwise, the
198  * zero-based index of this mark into the parent panel's <tt>children</tt> array.
199  *
200  * @type number
201  */
202 pv.Mark.prototype.childIndex = -1;
203 
204 /**
205  * The mark index. The value of this field depends on which instance (i.e.,
206  * which element of the data array) is currently being evaluated. During the
207  * build phase, the index is incremented over each datum; when handling events,
208  * the index is set to the instance that triggered the event.
209  *
210  * @type number
211  */
212 pv.Mark.prototype.index = -1;
213 
214 /**
215  * The scene graph. The scene graph is an array of objects; each object (or
216  * "node") corresponds to an instance of this mark and an element in the data
217  * array. The scene graph can be traversed to lookup previously-evaluated
218  * properties.
219  *
220  * <p>For instance, consider a stacked area chart. The bottom property of the
221  * area can be defined using the <i>cousin</i> instance, which is the current
222  * area instance in the previous instantiation of the parent panel. In this
223  * sample code,
224  *
225  * <pre>new pv.Panel()
226  *     .width(150).height(150)
227  *   .add(pv.Panel)
228  *     .data([[1, 1.2, 1.7, 1.5, 1.7],
229  *            [.5, 1, .8, 1.1, 1.3],
230  *            [.2, .5, .8, .9, 1]])
231  *   .add(pv.Area)
232  *     .data(function(d) d)
233  *     .bottom(function() {
234  *         var c = this.cousin();
235  *         return c ? (c.bottom + c.height) : 0;
236  *       })
237  *     .height(function(d) d * 40)
238  *     .left(function() this.index * 35)
239  *   .root.render();</pre>
240  *
241  * the bottom property is computed based on the upper edge of the corresponding
242  * datum in the previous series. The area's parent panel is instantiated once
243  * per series, so the cousin refers to the previous (below) area mark. (Note
244  * that the position of the upper edge is not the same as the top property,
245  * which refers to the top margin: the distance from the top edge of the panel
246  * to the top edge of the mark.)
247  *
248  * @see #first
249  * @see #last
250  * @see #sibling
251  * @see #cousin
252  * @name pv.Mark.prototype.scene
253  */
254 
255 /**
256  * The root parent panel. This may be undefined for "offscreen" marks that are
257  * created for inheritance purposes only.
258  *
259  * @type pv.Panel
260  * @name pv.Mark.prototype.root
261  */
262 
263 /**
264  * The data property; an array of objects. The size of the array determines the
265  * number of marks that will be instantiated; each element in the array will be
266  * passed to property functions to compute the property values. Typically, the
267  * data property is specified as a constant array, such as
268  *
269  * <pre>m.data([1, 2, 3, 4, 5]);</pre>
270  *
271  * However, it is perfectly acceptable to define the data property as a
272  * function. This function might compute the data dynamically, allowing
273  * different data to be used per enclosing panel. For instance, in the stacked
274  * area graph example (see {@link #scene}), the data function on the area mark
275  * dereferences each series.
276  *
277  * @type array
278  * @name pv.Mark.prototype.data
279  */
280 
281 /**
282  * The visible property; a boolean determining whether or not the mark instance
283  * is visible. If a mark instance is not visible, its other properties will not
284  * be evaluated. Similarly, for panels no child marks will be rendered.
285  *
286  * @type boolean
287  * @name pv.Mark.prototype.visible
288  */
289 
290 /**
291  * The left margin; the distance, in pixels, between the left edge of the
292  * enclosing panel and the left edge of this mark. Note that in some cases this
293  * property may be redundant with the right property, or with the conjunction of
294  * right and width.
295  *
296  * @type number
297  * @name pv.Mark.prototype.left
298  */
299 
300 /**
301  * The right margin; the distance, in pixels, between the right edge of the
302  * enclosing panel and the right edge of this mark. Note that in some cases this
303  * property may be redundant with the left property, or with the conjunction of
304  * left and width.
305  *
306  * @type number
307  * @name pv.Mark.prototype.right
308  */
309 
310 /**
311  * The top margin; the distance, in pixels, between the top edge of the
312  * enclosing panel and the top edge of this mark. Note that in some cases this
313  * property may be redundant with the bottom property, or with the conjunction
314  * of bottom and height.
315  *
316  * @type number
317  * @name pv.Mark.prototype.top
318  */
319 
320 /**
321  * The bottom margin; the distance, in pixels, between the bottom edge of the
322  * enclosing panel and the bottom edge of this mark. Note that in some cases
323  * this property may be redundant with the top property, or with the conjunction
324  * of top and height.
325  *
326  * @type number
327  * @name pv.Mark.prototype.bottom
328  */
329 
330 /**
331  * The cursor property; corresponds to the CSS cursor property. This is
332  * typically used in conjunction with event handlers to indicate interactivity.
333  *
334  * @type string
335  * @name pv.Mark.prototype.cursor
336  * @see <a href="http://www.w3.org/TR/CSS2/ui.html#propdef-cursor">CSS2 cursor</a>
337  */
338 
339 /**
340  * The title property; corresponds to the HTML/SVG title property, allowing the
341  * general of simple plain text tooltips.
342  *
343  * @type string
344  * @name pv.Mark.prototype.title
345  */
346 
347 /**
348  * The reverse property; a boolean determining whether marks are ordered from
349  * front-to-back or back-to-front. SVG does not support explicit z-ordering;
350  * shapes are rendered in the order they appear. Thus, by default, marks are
351  * rendered in data order. Setting the reverse property to false reverses the
352  * order in which they are rendered; however, the properties are still evaluated
353  * (i.e., built) in forward order.
354  *
355  * @type boolean
356  * @name pv.Mark.prototype.reverse
357  */
358 
359 /**
360  * Default properties for all mark types. By default, the data array is the
361  * parent data as a single-element array; if the data property is not specified,
362  * this causes each mark to be instantiated as a singleton with the parents
363  * datum. The visible property is true by default, and the reverse property is
364  * false.
365  *
366  * @type pv.Mark
367  */
368 pv.Mark.prototype.defaults = new pv.Mark()
369     .data(function(d) { return [d]; })
370     .visible(true)
371     .reverse(false)
372     .cursor("")
373     .title("");
374 
375 /* Private categorical colors for default fill & stroke styles. */
376 var defaultFillStyle = pv.Colors.category20().by(pv.parent),
377     defaultStrokeStyle = pv.Colors.category10().by(pv.parent);
378 
379 /**
380  * Sets the prototype of this mark to the specified mark. Any properties not
381  * defined on this mark may be inherited from the specified prototype mark, or
382  * its prototype, and so on. The prototype mark need not be the same type of
383  * mark as this mark. (Note that for inheritance to be useful, properties with
384  * the same name on different mark types should have equivalent meaning.)
385  *
386  * @param {pv.Mark} proto the new prototype.
387  * @return {pv.Mark} this mark.
388  * @see #add
389  */
390 pv.Mark.prototype.extend = function(proto) {
391   this.proto = proto;
392   return this;
393 };
394 
395 /**
396  * Adds a new mark of the specified type to the enclosing parent panel, whilst
397  * simultaneously setting the prototype of the new mark to be this mark.
398  *
399  * @param {function} type the type of mark to add; a constructor, such as
400  * <tt>pv.Bar</tt>.
401  * @return {pv.Mark} the new mark.
402  * @see #extend
403  */
404 pv.Mark.prototype.add = function(type) {
405   return this.parent.add(type).extend(this);
406 };
407 
408 /**
409  * Defines a local variable on this mark. Local variables are initialized once
410  * per mark (i.e., per parent panel instance), and can be used to store local
411  * state for the mark. Here are a few reasons you might want to use
412  * <tt>def</tt>:
413  *
414  * <p>1. To store local state. For example, say you were visualizing employment
415  * statistics, and your root panel had an array of occupations. In a child
416  * panel, you might want to initialize a local scale, and reference it from a
417  * property function:
418  *
419  * <pre>.def("y", function(d) pv.Scale.linear(0, pv.max(d.values)).range(0, h))
420  * .height(function(d) this.y()(d))</pre>
421  *
422  * In this example, <tt>this.y()</tt> returns the defined local scale. We then
423  * invoke the scale function, passing in the datum, to compute the height.  Note
424  * that defs are similar to fixed properties: they are only evaluated once per
425  * parent panel, and <tt>this.y()</tt> returns a function, rather than
426  * automatically evaluating this function as a property.
427  *
428  * <p>2. To store temporary state for interaction. Say you have an array of
429  * bars, and you want to color the bar differently if the mouse is over it. Use
430  * <tt>def</tt> to define a local variable, and event handlers to override this
431  * variable interactively:
432  *
433  * <pre>.def("i", -1)
434  * .event("mouseover", function() this.i(this.index))
435  * .event("mouseout", function() this.i(-1))
436  * .fillStyle(function() this.i() == this.index ? "red" : "blue")</pre>
437  *
438  * Notice that <tt>this.i()</tt> can be used both to set the value of <i>i</i>
439  * (when an argument is specified), and to get the value of <i>i</i> (when no
440  * arguments are specified). In this way, it's like other property methods.
441  *
442  * <p>3. To specify fixed properties efficiently. Sometimes, the value of a
443  * property may be locally a constant, but dependent on parent panel data which
444  * is variable. In this scenario, you can use <tt>def</tt> to define a property;
445  * it will only get computed once per mark, rather than once per datum.
446  *
447  * @param {string} name the name of the local variable.
448  * @param {function} [value] an optional initializer; may be a constant or a
449  * function.
450  */
451 pv.Mark.prototype.def = function(name, value) {
452   this.$properties.push({
453       name: name,
454       type: (typeof value == "function") ? 1 : 0,
455       value: value
456     });
457   return this;
458 };
459 
460 /**
461  * Returns an anchor with the specified name. While anchor names are typically
462  * constants, the anchor name is a true property, which means you can specify a
463  * function to compute the anchor name dynamically. See the
464  * {@link pv.Anchor#name} property for details.
465  *
466  * @param {string} name the anchor name; either a string or a property function.
467  * @returns {pv.Anchor} the new anchor.
468  */
469 pv.Mark.prototype.anchor = function(name) {
470   var anchor = new pv.Anchor().extend(this).name(name);
471   anchor.parent = this.parent;
472   return anchor;
473 };
474 
475 /**
476  * Returns the anchor target of this mark, if it is derived from an anchor;
477  * otherwise returns null. For example, if a label is derived from a bar anchor,
478  *
479  * <pre>bar.anchor("top").add(pv.Label);</pre>
480  *
481  * then property functions on the label can refer to the bar via the
482  * <tt>anchorTarget</tt> method. This method is also useful for mark types
483  * defining properties on custom anchors.
484  *
485  * @returns {pv.Mark} the anchor target of this mark; possibly null.
486  */
487 pv.Mark.prototype.anchorTarget = function() {
488   var target = this;
489   while (!(target instanceof pv.Anchor)) {
490     target = target.proto;
491     if (!target) return null;
492   }
493   return target.proto;
494 };
495 
496 /**
497  * Returns the first instance of this mark in the scene graph. This method can
498  * only be called when the mark is bound to the scene graph (for example, from
499  * an event handler, or within a property function).
500  *
501  * @returns a node in the scene graph.
502  */
503 pv.Mark.prototype.first = function() {
504   return this.scene[0];
505 };
506 
507 /**
508  * Returns the last instance of this mark in the scene graph. This method can
509  * only be called when the mark is bound to the scene graph (for example, from
510  * an event handler, or within a property function). In addition, note that mark
511  * instances are built sequentially, so the last instance of this mark may not
512  * yet be constructed.
513  *
514  * @returns a node in the scene graph.
515  */
516 pv.Mark.prototype.last = function() {
517   return this.scene[this.scene.length - 1];
518 };
519 
520 /**
521  * Returns the previous instance of this mark in the scene graph, or null if
522  * this is the first instance.
523  *
524  * @returns a node in the scene graph, or null.
525  */
526 pv.Mark.prototype.sibling = function() {
527   return (this.index == 0) ? null : this.scene[this.index - 1];
528 };
529 
530 /**
531  * Returns the current instance in the scene graph of this mark, in the previous
532  * instance of the enclosing parent panel. May return null if this instance
533  * could not be found. See the {@link pv.Layout.stack} function for an example
534  * property function using cousin.
535  *
536  * @see pv.Layout.stack
537  * @returns a node in the scene graph, or null.
538  */
539 pv.Mark.prototype.cousin = function() {
540   var p = this.parent, s = p && p.sibling();
541   return (s && s.children) ? s.children[this.childIndex][this.index] : null;
542 };
543 
544 /**
545  * Renders this mark, including recursively rendering all child marks if this is
546  * a panel.
547  */
548 pv.Mark.prototype.render = function() {
549   /*
550    * Rendering consists of three phases: bind, build and update. The update
551    * phase is decoupled to allow different rendering engines.
552    *
553    * In the bind phase, inherited property definitions are cached so they do not
554    * need to be queried during build. In the build phase, properties are
555    * evaluated, and the scene graph is generated. In the update phase, the scene
556    * is rendered by creating and updating elements and attributes in the SVG
557    * image. No properties are evaluated during the update phase; instead the
558    * values computed previously in the build phase are simply translated into
559    * SVG.
560    */
561   this.bind();
562   this.build();
563   pv.Scene.updateAll(this.scene);
564 };
565 
566 /** @private Computes the root data stack for the specified mark. */
567 function argv(mark) {
568   var stack = [];
569   while (mark) {
570     stack.push(mark.scene[mark.index].data);
571     mark = mark.parent;
572   }
573   return stack;
574 }
575 
576 /** @private TODO */
577 pv.Mark.prototype.bind = function() {
578   var seen = {}, types = [[], [], [], []], data, visible;
579 
580   /** TODO */
581   function bind(mark) {
582     do {
583       var properties = mark.$properties;
584       for (var i = properties.length - 1; i >= 0 ; i--) {
585         var p = properties[i];
586         if (!(p.name in seen)) {
587           seen[p.name] = 1;
588           switch (p.name) {
589             case "data": data = p; break;
590             case "visible": visible = p; break;
591             default: types[p.type].push(p); break;
592           }
593         }
594       }
595     } while (mark = mark.proto);
596   }
597 
598   /** TODO */
599   function def(name) {
600     return function(v) {
601       var defs = this.scene.defs;
602       if (arguments.length) {
603         if (v == undefined) {
604           delete defs.locked[name];
605         } else {
606           defs.locked[name] = true;
607         }
608         defs.values[name] = v;
609         return this;
610       } else {
611         return defs.values[name];
612       }
613     };
614   }
615 
616   /* Scan the proto chain for all defined properties. */
617   bind(this);
618   bind(this.defaults);
619   types[1].reverse();
620   types[3].reverse();
621 
622   /* Any undefined properties are null. */
623   var mark = this;
624   do for (var name in mark.properties) {
625     if (!(name in seen)) {
626       seen[name] = 1;
627       types[2].push({name: name, type: 2, value: null});
628     }
629   } while (mark = mark.proto);
630 
631   /* Define setter-getter for inherited defs. */
632   var defs = types[0].concat(types[1]);
633   for (var i = 0; i < defs.length; i++) {
634     var d = defs[i];
635     this[d.name] = def(d.name);
636   }
637 
638   /* Setup binds to evaluate constants before functions. */
639   this.binds = {
640     data: data,
641     visible: visible,
642     defs: defs,
643     properties: pv.blend(types)
644   };
645 };
646 
647 /**
648  * @private Evaluates properties and computes implied properties. Properties are
649  * stored in the {@link #scene} array for each instance of this mark.
650  *
651  * <p>As marks are built recursively, the {@link #index} property is updated to
652  * match the current index into the data array for each mark. Note that the
653  * index property is only set for the mark currently being built and its
654  * enclosing parent panels. The index property for other marks is unset, but is
655  * inherited from the global <tt>Mark</tt> class prototype. This allows mark
656  * properties to refer to properties on other marks <i>in the same panel</i>
657  * conveniently; however, in general it is better to reference mark instances
658  * specifically through the scene graph rather than depending on the magical
659  * behavior of {@link #index}.
660  *
661  * <p>The root scene array has a special property, <tt>data</tt>, which stores
662  * the current data stack. The first element in this stack is the current datum,
663  * followed by the datum of the enclosing parent panel, and so on. The data
664  * stack should not be accessed directly; instead, property functions are passed
665  * the current data stack as arguments.
666  *
667  * <p>The evaluation of the <tt>data</tt> and <tt>visible</tt> properties is
668  * special. The <tt>data</tt> property is evaluated first; unlike the other
669  * properties, the data stack is from the parent panel, rather than the current
670  * mark, since the data is not defined until the data property is evaluated.
671  * The <tt>visisble</tt> property is subsequently evaluated for each instance;
672  * only if true will the {@link #buildInstance} method be called, evaluating
673  * other properties and recursively building the scene graph.
674  *
675  * <p>If this mark is being re-built, any old instances of this mark that no
676  * longer exist (because the new data array contains fewer elements) will be
677  * cleared using {@link #clearInstance}.
678  *
679  * @param parent the instance of the parent panel from the scene graph.
680  */
681 pv.Mark.prototype.build = function() {
682   var scene = this.scene;
683   if (!scene) {
684     scene = this.scene = [];
685     scene.mark = this;
686     scene.type = this.type;
687     scene.childIndex = this.childIndex;
688     if (this.parent) {
689       scene.parent = this.parent.scene;
690       scene.parentIndex = this.parent.index;
691     }
692   }
693 
694   /* Set the data stack. */
695   var stack = this.root.scene.data;
696   if (!stack) this.root.scene.data = stack = argv(this.parent);
697 
698   /* Evaluate defs. */
699   if (this.binds.defs.length) {
700     var defs = scene.defs;
701     if (!defs) scene.defs = defs = {values: {}, locked: {}};
702     for (var i = 0; i < this.binds.defs.length; i++) {
703       var d = this.binds.defs[i];
704       if (!(d.name in defs.locked)) {
705         var v = d.value;
706         if (d.type == 1) {
707           property = d.name;
708           v = v.apply(this, stack);
709         }
710         defs.values[d.name] = v;
711       }
712     }
713   }
714 
715   /* Evaluate special data property. */
716   var data = this.binds.data;
717   switch (data.type) {
718     case 0: case 1: data = defs.values.data; break;
719     case 2: data = data.value; break;
720     case 3: {
721       property = "data";
722       data = data.value.apply(this, stack);
723       break;
724     }
725   }
726 
727   /* Create, update and delete scene nodes. */
728   stack.unshift(null);
729   scene.length = data.length;
730   for (var i = 0; i < data.length; i++) {
731     pv.Mark.prototype.index = this.index = i;
732     var s = scene[i];
733     if (!s) scene[i] = s = {};
734     s.data = stack[0] = data[i];
735 
736     /* Evaluate special visible property. */
737     var visible = this.binds.visible;
738     switch (visible.type) {
739       case 0: case 1: visible = defs.values.visible; break;
740       case 2: visible = visible.value; break;
741       case 3: {
742         property = "visible";
743         visible = visible.value.apply(this, stack);
744         break;
745       }
746     }
747 
748     if (s.visible = visible) this.buildInstance(s);
749   }
750   stack.shift();
751   delete this.index;
752   pv.Mark.prototype.index = -1;
753   if (!this.parent) scene.data = null;
754 
755   return this;
756 };
757 
758 /**
759  * @private Evaluates the specified array of properties for the specified
760  * instance <tt>s</tt> in the scene graph.
761  *
762  * @param s a node in the scene graph; the instance of the mark to build.
763  * @param properties an array of properties.
764  */
765 pv.Mark.prototype.buildProperties = function(s, properties) {
766   for (var i = 0, n = properties.length; i < n; i++) {
767     var p = properties[i], v = p.value;
768     switch (p.type) {
769       case 0: case 1: v = this.scene.defs.values[p.name]; break;
770       case 3: {
771         property = p.name;
772         v = v.apply(this, this.root.scene.data);
773         break;
774       }
775     }
776     s[p.name] = v;
777   }
778 };
779 
780 /**
781  * @private Evaluates all of the properties for this mark for the specified
782  * instance <tt>s</tt> in the scene graph. The set of properties to evaluate is
783  * retrieved from the {@link #properties} array for this mark type (see {@link
784  * #type}).  After these properties are evaluated, any <b>implied</b> properties
785  * may be computed by the mark and set on the scene graph; see
786  * {@link #buildImplied}.
787  *
788  * <p>For panels, this method recursively builds the scene graph for all child
789  * marks as well. In general, this method should not need to be overridden by
790  * concrete mark types.
791  *
792  * @param s a node in the scene graph; the instance of the mark to build.
793  */
794 pv.Mark.prototype.buildInstance = function(s) {
795   this.buildProperties(s, this.binds.properties);
796   this.buildImplied(s);
797 };
798 
799 /**
800  * @private Computes the implied properties for this mark for the specified
801  * instance <tt>s</tt> in the scene graph. Implied properties are those with
802  * dependencies on multiple other properties; for example, the width property
803  * may be implied if the left and right properties are set. This method can be
804  * overridden by concrete mark types to define new implied properties, if
805  * necessary.
806  *
807  * @param s a node in the scene graph; the instance of the mark to build.
808  */
809 pv.Mark.prototype.buildImplied = function(s) {
810   var l = s.left;
811   var r = s.right;
812   var t = s.top;
813   var b = s.bottom;
814 
815   /* Assume width and height are zero if not supported by this mark type. */
816   var p = this.properties;
817   var w = p.width ? s.width : 0;
818   var h = p.height ? s.height : 0;
819 
820   /* Compute implied width, right and left. */
821   var width = this.parent ? this.parent.width() : (w + l + r);
822   if (w == null) {
823     w = width - (r = r || 0) - (l = l || 0);
824   } else if (r == null) {
825     r = width - w - (l = l || 0);
826   } else if (l == null) {
827     l = width - w - (r = r || 0);
828   }
829 
830   /* Compute implied height, bottom and top. */
831   var height = this.parent ? this.parent.height() : (h + t + b);
832   if (h == null) {
833     h = height - (t = t || 0) - (b = b || 0);
834   } else if (b == null) {
835     b = height - h - (t = t || 0);
836   } else if (t == null) {
837     t = height - h - (b = b || 0);
838   }
839 
840   s.left = l;
841   s.right = r;
842   s.top = t;
843   s.bottom = b;
844 
845   /* Only set width and height if they are supported by this mark type. */
846   if (p.width) s.width = w;
847   if (p.height) s.height = h;
848 };
849 
850 /**
851  * @private The name of the property being evaluated, for so-called "smart"
852  * functions that change behavior depending on which property is being
853  * evaluated. This functionality is somewhat magical, so for now, this feature
854  * is not exposed outside the library.
855  *
856  * @type string
857  */
858 var property;
859 
860 /** @private The current mouse location. */
861 var pageX = 0, pageY = 0;
862 pv.listen(window, "mousemove", function(e) { pageX = e.pageX; pageY = e.pageY; });
863 
864 /**
865  * Returns the current location of the mouse (cursor) relative to this mark's
866  * parent. The <i>x</i> coordinate corresponds to the left margin, while the
867  * <i>y</i> coordinate corresponds to the top margin.
868  *
869  * @returns {pv.Vector} the mouse location.
870  */
871 pv.Mark.prototype.mouse = function() {
872   var x = 0, y = 0, mark = (this instanceof pv.Panel) ? this : this.parent;
873   do {
874     x += mark.left();
875     y += mark.top();
876   } while (mark = mark.parent);
877   var node = this.root.canvas();
878   do {
879     x += node.offsetLeft;
880     y += node.offsetTop;
881   } while (node = node.offsetParent);
882   return pv.vector(pageX - x, pageY - y);
883 };
884 
885 /**
886  * Registers an event handler for the specified event type with this mark. When
887  * an event of the specified type is triggered, the specified handler will be
888  * invoked. The handler is invoked in a similar method to property functions:
889  * the context is <tt>this</tt> mark instance, and the arguments are the full
890  * data stack. Event handlers can use property methods to manipulate the display
891  * properties of the mark:
892  *
893  * <pre>m.event("click", function() this.fillStyle("red"));</pre>
894  *
895  * Alternatively, the external data can be manipulated and the visualization
896  * redrawn:
897  *
898  * <pre>m.event("click", function(d) {
899  *     data = all.filter(function(k) k.name == d);
900  *     vis.render();
901  *   });</pre>
902  *
903  * The return value of the event handler determines which mark gets re-rendered.
904  * Use defs ({@link #def}) to set temporary state from event handlers.
905  *
906  * <p>The complete set of event types is defined by SVG; see the reference
907  * below. The set of supported event types is:<ul>
908  *
909  * <li>click
910  * <li>mousedown
911  * <li>mouseup
912  * <li>mouseover
913  * <li>mousemove
914  * <li>mouseout
915  *
916  * </ul>Since Protovis does not specify any concept of focus, it does not
917  * support key events; these should be handled outside the visualization using
918  * standard JavaScript. In the future, support for interaction may be extended
919  * to support additional event types, particularly those most relevant to
920  * interactive visualization, such as selection.
921  *
922  * <p>TODO In the current implementation, event handlers are not inherited from
923  * prototype marks. They must be defined explicitly on each interactive mark. In
924  * addition, only one event handler for a given event type can be defined; when
925  * specifying multiple event handlers for the same type, only the last one will
926  * be used.
927  *
928  * @see <a href="http://www.w3.org/TR/SVGTiny12/interact.html#SVGEvents">SVG events</a>
929  * @param {string} type the event type.
930  * @param {function} handler the event handler.
931  * @returns {pv.Mark} this.
932  */
933 pv.Mark.prototype.event = function(type, handler) {
934   if (!this.$handlers) this.$handlers = {};
935   this.$handlers[type] = handler;
936   return this;
937 };
938 
939 /** @private TODO */
940 pv.Mark.prototype.dispatch = function(type, scenes, index) {
941   var l = this.$handlers && this.$handlers[type];
942   if (!l) {
943     if (this.parent) {
944       this.parent.dispatch(type, scenes.parent, scenes.parentIndex);
945     }
946     return;
947   }
948   try {
949 
950     /* Setup the scene stack. */
951     var mark = this;
952     do {
953       mark.index = index;
954       mark.scene = scenes;
955       index = scenes.parentIndex;
956       scenes = scenes.parent;
957     } while (mark = mark.parent);
958 
959     /* Execute the event listener. */
960     try {
961       mark = l.apply(this, this.root.scene.data = argv(this));
962     } finally {
963       this.root.scene.data = null;
964     }
965 
966     /* Update the display. TODO dirtying. */
967     if (mark instanceof pv.Mark) mark.render();
968 
969   } finally {
970 
971     /* Restore the scene stack. */
972     var mark = this;
973     do {
974       if (mark.parent) delete mark.scene;
975       delete mark.index;
976     } while (mark = mark.parent);
977   }
978 };
979